
#ifndef SX_QVIEWPORT_FACTORY_H
#define SX_QVIEWPORT_FACTORY_H

#include <sxGraphicsContext.h>
#include <sxQViewport.h>
#include <sxQViewportFrame.h>

namespace Sx {
namespace QtInterface {

template <typename QViewportFrameType, typename ContextType, typename QViewportType>
class QViewportFactory {
	static_assert(std::is_base_of<QViewport, QViewportType>::value, "[QViewportFactory] Compile Error: Template type QViewportType must extend class QViewport.");
	static_assert(std::is_base_of<QViewportFrame, QViewportFrameType>::value, "[QViewportFactory] Compile Error: Template type QViewportFrameType must extend class QViewportFrame.");
	static_assert(std::is_base_of<GraphicsContext, ContextType>::value, "[QViewportFactory] Compile Error: Template type ContextType must extend class GraphicsContext.");

public:
	static QViewportFactory& getInstance();

	QViewportFrameType* createViewportFrame(QWidget* parent, const std::shared_ptr<ContextType>& context, const std::shared_ptr<ViewportController>& controller = nullptr, Qt::WFlags flags = 0);
	QViewportFrameType* createSharedViewportFrame(QWidget* parent, QViewportType* share, const std::shared_ptr<ViewportController>& controller = nullptr, Qt::WFlags flags = 0);

private:
	QViewportFactory();
	QViewportFactory(const QViewportFactory& viewportFactory);
	~QViewportFactory();

	QViewportFactory& operator = (const QViewportFactory& factory);
};

template <typename QViewportFrameType, typename ContextType, typename QViewportType>
Sx::QtInterface::QViewportFactory<QViewportFrameType, ContextType, QViewportType>& Sx::QtInterface::QViewportFactory<QViewportFrameType, ContextType, QViewportType>::getInstance() {
	static QViewportFactory viewportFactory;
	return viewportFactory;
}

template <typename QViewportFrameType, typename ContextType, typename QViewportType>
QViewportFrameType* QViewportFactory<QViewportFrameType, ContextType, QViewportType>::createViewportFrame(QWidget* parent, const std::shared_ptr<ContextType>& context, const std::shared_ptr<ViewportController>& controller, Qt::WFlags flags) {
	QViewportType* viewport = new QViewportType(nullptr, context);
	QViewportFrameType* frame = new QViewportFrameType(parent, viewport, controller, flags);
	viewport->setParent(frame);
	return frame;
}

template <typename QViewportFrameType, typename ContextType, typename QViewportType>
QViewportFrameType* QViewportFactory<QViewportFrameType, ContextType, QViewportType>::createSharedViewportFrame(QWidget* parent, QViewportType* share, const std::shared_ptr<ViewportController>& controller, Qt::WFlags flags) {
	QViewportType* viewport = new QViewportType(nullptr, share);
	QViewportFrameType* frame = new QViewportFrameType(parent, viewport, controller, flags);
	return frame;
}

template <typename QViewportFrameType, typename ContextType, typename QViewportType>
Sx::QtInterface::QViewportFactory<QViewportFrameType, ContextType, QViewportType>::QViewportFactory() {}

template <typename QViewportFrameType, typename ContextType, typename QViewportType>
Sx::QtInterface::QViewportFactory<QViewportFrameType, ContextType, QViewportType>::QViewportFactory(const QViewportFactory& viewportFactory) {}

template <typename QViewportFrameType, typename ContextType, typename QViewportType>
Sx::QtInterface::QViewportFactory<QViewportFrameType, ContextType, QViewportType>::~QViewportFactory() {}

template <typename QViewportFrameType, typename ContextType, typename QViewportType>
Sx::QtInterface::QViewportFactory<QViewportFrameType, ContextType, QViewportType>& Sx::QtInterface::QViewportFactory<QViewportFrameType, ContextType, QViewportType>::operator = (const QViewportFactory& factory) {
	return QViewportFactory::getInstance();
}

}

}

#endif
